package com.panopset;

import java.util.prefs.AbstractPreferences;
import java.util.prefs.BackingStoreException;

/**
 * This class was constructed mostly from reply 24 from the Sun forum thread
 * referenced below.
 *
 * * <h5>References</h5>
 * <ul>
 * <li>
 * <a href="http://forums.sun.com/thread.jspa?threadID=477461">
 * http://forums.sun.com/thread.jspa?threadID=477461 </a></li>
 * </ul>
 *
 *
 * Utility class that encodes and decodes byte arrays in Base64 representation.
 * Uses underlying functionality in the java.util.prefs package of the Java API.
 * Note that this is slightly different from RFC 2045; ie, there are no CRLFs in
 * the encoded string.
 */
public final class Base64 extends AbstractPreferences {

    /**
     * Store.
     */
    private String store;

    /**
     * Encode a String.
     *
     * @param s
     *            String to encode.
     * @return Base64 representation as a String.
     */
    public static synchronized String encode(final String s) {
        return encode(s.getBytes());
    }

    /** Given a byte array, return its Base64 representation as a String. */
    /**
     * Encode a byte array.
     *
     * @param b
     *            Byte array to encode.
     * @return Base64 representation as a String.
     */
    public static synchronized String encode(final byte[] b) {
        getInstance().putByteArray(null, b);
        return getInstance().get(null, null);
    }

    /**
     * Given a String containing a Base64 representation, return the
     * corresponding byte array.
     *
     * @param base64String
     *            Encoded String.
     * @return Decoded String.
     */
    public static synchronized byte[] decode(final String base64String) {
        getInstance().put(null, base64String);
        return getInstance().getByteArray(null, null);
    }

    /**
     * Get stored value.
     * @param key Ignored.
     * @param def Ignored.
     * @return stored value.
     */
    public String get(final String key, final String def) {
        return store;
    }

    /**
     * Put a value in storage.
     * @param key Ignored.
     * @param value Value to store.
     */
    public void put(final String key, final String value) {
        store = value;
    }

    /**
     * Based on SingletonHolder inner class by Bill Pugh.
     *
     * <h5>References</h5>
     * <ul>
     * <li>
     * <a href="http://en.wikipedia.org/wiki/Singleton_pattern">
     * http://en.wikipedia.org/wiki/Singleton_pattern </a></li>
     * </ul>
     *
     */
    private static final class Singleton {
        /**
         * Instance variable.
         */
        private static final Base64 INSTANCE = new Base64();

        /**
         * Private constructor.
         */
        private Singleton() {
            // Prevent instantiation.
        }
    }

    /**
     * @return static FlagIcons instance.
     */
    protected static Base64 getInstance() {
        return Singleton.INSTANCE;
    }

    /**
     * Private singleton constructor.
     */
    private Base64() {
        super(null, "");
    }

    /**
     * dummy implementation as AbstractPreferences is extended to get access to
     * protected methods.
     *
     * @param name
     *            Name, not used.
     * @return Abstract preferences, returns null.
     */
    protected AbstractPreferences childSpi(final String name) {
        return null;
    }

    /**
     * Dummy.
     *
     * @return null.
     * @throws BackingStoreException
     *             Backing Store Exception.
     */
    protected String[] childrenNamesSpi() throws BackingStoreException {
        return null;
    }

    /**
     * Dummy.
     *
     * @throws BackingStoreException
     *             Backing Store Exception.
     */
    protected void flushSpi() throws BackingStoreException {
    }

    /**
     * Dummy.
     *
     * @param key
     *            Not used.
     * @return null.
     */
    protected String getSpi(final String key) {
        return null;
    }

    /**
     * Dummy.
     *
     * @return null.
     * @throws BackingStoreException
     *             Backing Store Exception.
     */
    protected String[] keysSpi() throws BackingStoreException {
        return null;
    }

    /**
     * Dummy.
     *
     * @param key
     *            Not used.
     * @param value
     *            Not used.
     */
    protected void putSpi(final String key, final String value) {
    }

    /**
     * Dummy.
     *
     * @throws BackingStoreException
     *             Backing Store Exception.
     */
    protected void removeNodeSpi() throws BackingStoreException {
    }

    /**
     * Dummy.
     *
     * @param key
     *            Not used.
     */
    protected void removeSpi(final String key) {
    }

    /**
     * Dummy.
     *
     * @throws BackingStoreException
     *             Backing Store Exception.
     */
    protected void syncSpi() throws BackingStoreException {
    }
}
